package com.ler.yrmall.product.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ler.yrmall.product.entity.CategoryEntity;
import com.ler.yrmall.product.mapper.CategoryMapper;
import com.ler.yrmall.product.service.CategoryBrandRelationService;
import com.ler.yrmall.product.service.CategoryService;
import com.ler.yrmall.product.vo.Category2VO;
import com.ler.yrmall.product.vo.CategoryVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * @author leron
 */
@Service
@Slf4j
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, CategoryEntity> implements CategoryService {

    @Resource
    private CategoryBrandRelationService categoryBrandRelationService;

    @Override
    public List<CategoryVO> listWithTree() {
        List<CategoryEntity> entities = this.list(Wrappers.<CategoryEntity>lambdaQuery().orderByAsc(CategoryEntity::getSort));
        List<CategoryVO> categoryList = BeanUtil.copyToList(entities, CategoryVO.class);
        return categoryList.stream()
                .filter(item -> item.getParentCid() == 0)
                .peek(item -> item.setChildren(getChildren(item,categoryList)))
                .collect(Collectors.toList());
    }

    @Override
    public void removeMenuByIds(List<Long> ids) {
        ids.forEach(item -> {
            if (baseMapper.selectCountMenuByParentId() != 0){
                throw new RuntimeException("该菜单不允许删除");
            }
        });
        baseMapper.deleteBatchIds(ids);
    }

    private List<CategoryVO> getChildren(CategoryVO current,List<CategoryVO> all){
        return all.stream().filter(item -> item.getParentCid().equals(current.getId())).map(item -> {
            if (getChildren(item,all).size() == 0){
                return item;
            }
            item.setChildren(getChildren(item,all));
            return item;
        }).collect(Collectors.toList());
    }

    @Override
    public Long[] getCategoryPath(Long categoryId) {
        List<Long> path = new ArrayList<>();
        List<Long> categoryParentPath = getCategoryParentPath(categoryId, path);
        Collections.reverse(categoryParentPath);
        return categoryParentPath.toArray(new Long[0]);
    }

    private List<Long> getCategoryParentPath(Long categoryId, List<Long> path){
        CategoryEntity categoryEntity = this.getById(categoryId);
        path.add(categoryId);
        if (categoryEntity.getParentCid() != 0){
            getCategoryParentPath(categoryEntity.getParentCid(),path);
        }
        return path;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(CategoryEntity category) {
        this.updateById(category);
    }

    @Override
    public List<CategoryEntity> getLevelOne() {
        return this.list(Wrappers.<CategoryEntity>lambdaQuery().eq(CategoryEntity::getParentCid,0));
    }

    @Override
    @Cacheable(value = {"categoryJson"},key = "'catagory'")
    public Map<String, List<Category2VO>> getCatalogJson() {
        //查询所有的一级分类
        return getLevelOne().stream().collect(Collectors.toMap(k -> k.getId().toString(), v -> {
            //查询所有的二级分类
            QueryWrapper<CategoryEntity> wrapper = new QueryWrapper<>();
            wrapper.eq("parent_cid", v.getId());
            List<CategoryEntity> catalog2s = this.list(wrapper);
            List<Category2VO> catalog2VOS = new ArrayList<>();
            if (catalog2s != null) {
                catalog2s.forEach(item -> {
                    Category2VO catalog2VO = new Category2VO();
                    catalog2VO.setCatalog1Id(v.getId().toString());
                    catalog2VO.setId(item.getId().toString());
                    catalog2VO.setName(item.getName());
                    catalog2VOS.add(catalog2VO);
                    List<Category2VO.Catalog3VO> catalog3VOS = new ArrayList<>();
                    //查询三级分类
                    QueryWrapper<CategoryEntity> wrapper2 = new QueryWrapper<>();
                    wrapper2.eq("parent_cid", item.getId());
                    List<CategoryEntity> catalog3s = this.list(wrapper2);
                    if (catalog3s != null) {
                        catalog3s.forEach(l3 -> {
                            Category2VO.Catalog3VO catalog3VO = new Category2VO.Catalog3VO();
                            catalog3VO.setCatalog2Id(item.getId().toString());
                            catalog3VO.setName(l3.getName());
                            catalog3VO.setId(l3.getId().toString());
                            catalog3VOS.add(catalog3VO);
                        });
                    }
                    catalog2VO.setCatalog3List(catalog3VOS);
                });
            }
            return catalog2VOS;
        }));
    }

    @Override
    public CategoryVO getTreeByPid(long pid) {
        CategoryEntity categoryEntity = this.getById(pid);
        CategoryVO root = BeanUtil.copyProperties(categoryEntity, CategoryVO.class);
        List<CategoryEntity> lv2List = this.list(Wrappers.<CategoryEntity>lambdaQuery().eq(CategoryEntity::getParentCid, pid));
        List<CategoryVO> v2Target = BeanUtil.copyToList(lv2List, CategoryVO.class);
        root.setChildren(v2Target);
        List<Long> lv2Ids = lv2List.stream().map(CategoryEntity::getId).collect(Collectors.toList());
        List<CategoryEntity> lv3List = this.list(Wrappers.<CategoryEntity>lambdaQuery().in(CategoryEntity::getParentCid, lv2Ids));
        List<CategoryVO> v3Target = BeanUtil.copyToList(lv3List, CategoryVO.class);
        Map<Long, List<CategoryVO>> lv3Map = v3Target.stream().collect(Collectors.groupingBy(CategoryVO::getParentCid));
        v2Target.forEach(item -> item.setChildren(lv3Map.get(item.getId())));
        String str = JSON.toJSONString(root);
        return JSON.parseObject(str, new TypeReference<CategoryVO>() {});
    }
}